package ru.ifmo.ctd.year2008.notepad.diff;

import difflib.Chunk;
import difflib.Delta;
import difflib.DiffUtils;
import difflib.Patch;
import ru.ifmo.ctd.year2008.notepad.IdGenerator;
import ru.ifmo.ctd.year2008.notepad.Line;
import ru.ifmo.ctd.year2008.notepad.Text;

import java.util.ArrayList;
import java.util.List;

public class DiffCalculator {
    public static DiffSet getDiffSet(Text originalText, List<String> modifiedText, IdGenerator idGenerator) {
        List<Line> lines = originalText.getLines();
        List<String> originalStrings = getStrings(lines);
        Patch patch = DiffUtils.diff(originalStrings, modifiedText);
        List<Delta> deltas = patch.getDeltas();
        List<Diff> diffs = new ArrayList<Diff>(deltas.size());
        for (Delta delta: deltas) {
            Chunk chunkBefore = delta.getOriginal();
            Chunk chunkAfter = delta.getRevised();
            int pos = chunkBefore.getPosition();
            long afterWhatId = pos == 0? Diff.FIRST_LINE: lines.get(pos - 1).getId();
            int sizeBefore = chunkBefore.size();

            List<Line> linesBefore = new ArrayList<Line>(lines.subList(pos, pos + sizeBefore));
            List<Line> linesAfter = new ArrayList<Line>(chunkAfter.size());
            List<String> stringsAfter = (List<String>) chunkAfter.getLines();
            if (chunkAfter.size() == 1 && chunkBefore.size() == 1) {
                linesAfter.add(new Line(linesBefore.get(0).getId(), stringsAfter.get(0)));
            } else {
                for (String string: stringsAfter) {
                    linesAfter.add(new Line(idGenerator.getID(), string));
                }
            }
            diffs.add(new Diff(linesBefore, linesAfter, afterWhatId));
        }
        return new DiffSet(diffs);
    }

    private static List<String> getStrings(List<Line> lines) {
        List<String> strings = new ArrayList<String>(lines.size());
        for (Line line: lines) {
            strings.add(line.getString());
        }
        return strings;
    }



}
